Skip to content

allow to create war archive without copying massive files to exploded… - #21

Open
caiwei-ebay wants to merge 1 commit into
apache:masterfrom
caiwei-ebay:master
Open

allow to create war archive without copying massive files to exploded…#21
caiwei-ebay wants to merge 1 commit into
apache:masterfrom
caiwei-ebay:master

Conversation

@caiwei-ebay

Copy link
Copy Markdown

MWAR-445

This PR is initialized for discussion.
Basically the idea is to create the war archive without massive file copyings to exploded war directory to make maven-war-plugin run faster.

Please share your thoughts on it.

@michael-o

Copy link
Copy Markdown
Member

Doens't this only make sense in war:war goal?

@elharo
elharo requested a review from Copilot July 28, 2026 11:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR introduces an option to build the WAR archive directly from source paths (skipping most copies into an exploded webapp directory) to speed up maven-war-plugin execution.

Changes:

  • Added WarResourceCopy to track source→target mappings and optionally skip physical copies.
  • Added SourceTargetMappingResourceFilter to apply include/exclude filtering over the collected mappings and feed resources directly to WarArchiver.
  • Extended packaging flow and context APIs to support skipExplodedWarCreation, and updated WarMojo / classes packaging to use the new mode.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/main/java/org/apache/maven/plugins/war/util/WarResourceCopy.java New helper to record file mappings and optionally avoid copying.
src/main/java/org/apache/maven/plugins/war/util/SourceTargetMappingResourceFilter.java New filtering/scanning layer to convert mappings into PlexusIoResources for archiving.
src/main/java/org/apache/maven/plugins/war/util/ClassesPackager.java Added an overload to package classes from an explicit (path→file) mapping.
src/main/java/org/apache/maven/plugins/war/packaging/WarProjectPackagingTask.java Adjusted logging to reflect “collecting” vs “copying” behavior.
src/main/java/org/apache/maven/plugins/war/packaging/WarPackagingContext.java Added skipExplodedWarCreation() and getWarResourceCopy() hooks to the context API.
src/main/java/org/apache/maven/plugins/war/packaging/ClassesPackagingTask.java Records generated artifact mapping (WEB-INF/lib) into WarResourceCopy.
src/main/java/org/apache/maven/plugins/war/packaging/AbstractWarPackagingTask.java Routes file-copy operations through WarResourceCopy and records mappings.
src/main/java/org/apache/maven/plugins/war/WarMojo.java Builds WAR from mappings when skip mode is enabled, with a fallback addDirectory pass.
src/main/java/org/apache/maven/plugins/war/AbstractWarMojo.java Adds plugin parameter + propagates skip flag and returns WarPackagingContext from build methods.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

boolean archiveClasses();

/**
* Skip explded war creation, build web archive on source paths.
* @throws MojoFailureException In case of failure.
*/
public void buildExplodedWebapp( File webapplicationDirectory )
public WarPackagingContext buildExplodedWebapp( File webapplicationDirectory )
* @throws IOException if an error occurred while copying the files
*/
public void buildWebapp( MavenProject mavenProject, File webapplicationDirectory )
public WarPackagingContext buildWebapp( MavenProject mavenProject, File webapplicationDirectory )
Comment on lines +383 to +384
@Parameter( defaultValue = "false", name = "maven.war.exploded.skip" )
private boolean skipExplodedWarCreation;
Comment on lines +253 to +258
Map<String, File> map = context.getWarResourceCopy().getSourceTargetMappings();
if ( map.containsKey( "WEB-INF/web.xml" ) )
{
warArchiver.setWebxml( map.get( "WEB-INF/web.xml" ) );
map.remove( "WEB-INF/web.xml" );
}
Comment on lines +274 to +278
Set<String> targetPaths = context.getWarResourceCopy().getSourceTargetMappings().keySet();
Set<String> newExcludes = new HashSet<>( targetPaths );
newExcludes.addAll( Arrays.asList( getPackagingExcludes() ) );
warArchiver
.addDirectory( getWebappDirectory(), getPackagingIncludes(), newExcludes.toArray( new String[0] ) );
Comment on lines +59 to +62
for ( Map.Entry<String, File> entry : allClassFiles.entrySet() )
{
archiver.getArchiver().addFile( entry.getValue(), entry.getKey() );
}
Comment on lines +126 to +167
ds.setFilenameComparator( fileNameComparator );
ds.scan();

final Map<String, PlexusIoResource> result = new HashMap<>();
if ( isIncludingEmptyDirectories() )
{
String[] dirs = ds.getIncludedDirectories();
addResources( result, dirs );
}

String[] files = ds.getIncludedFiles();
addResources( result, files );
return result;
}

private void addResources( Map<String, PlexusIoResource> result, String[] resources )
throws IOException
{

final HashMap<Integer, String> cache1 = new HashMap<>();
final HashMap<Integer, String> cache2 = new HashMap<>();
for ( String name : resources )
{
File f = sourceTargetMappings.get( name );
if ( f != null )
{
PlexusIoResourceAttributes attrs = new FileAttributes( f, cache1, cache2 );
attrs = mergeAttributes( attrs, f.isDirectory() );

String remappedName = getName( name );

PlexusIoResource resource =
ResourceFactory.createResource( f, remappedName, null, getStreamTransformer(), attrs );

if ( isSelected( resource ) )
{
result.put( name, resource );
}
}

}
}
Comment on lines +372 to +396
String[] tokenizedName = tokenizePathToString( name, "/" );
if ( file.isFile() )
{
if ( isIncluded( name, tokenizedName ) )
{
if ( !isExcluded( name, tokenizedName ) )
{
filesIncluded.addElement( name );
}
else
{
everythingIncluded = false;
filesExcluded.addElement( name );
}
}
else
{
everythingIncluded = false;
filesNotIncluded.addElement( name );
}
}
else
{
throw new IllegalStateException( "Should not be here" );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants